
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import static java.util.Calendar.MONTH;
import static java.util.Calendar.YEAR;

public class GamePanel extends JPanel {
    private boolean isShowOrder = false;//记录显示
    public static final int EMPTY = 0;
    private final int BLACK = 1;
    private final int WHITE = 2;
    private int currentPlayer = BLACK;
    //该二维数组并保存棋盘上所有棋子的消息
    private ChessBean[][] chessBeans = new ChessBean[GameUtil.LINE_COUNT][GameUtil.LINE_COUNT];
    private int count = 1;//记录落子
    //转化为线坐标
    private int tx, ty;
    public boolean isGameOver = true;//标识游戏结束
    private boolean mode = true;
    private boolean intel = false;
    private int depth = 0;
    private int nodeCount = 0;
    private boolean soundswitch = true;
    Music music = new Music();
    long endTime;long startTime;

    public GamePanel() { //构造器  设置背景颜色
        this.setBackground(Color.ORANGE);
        this.setPreferredSize(new Dimension(GameUtil.PANEL_WIDTH, GameUtil.PANEL_HEIGHT));
        tx = 0;
        ty = 0;
        //    this.addMouseListener(mouseListener);
        //创建panel的时候把，chessBeans的位置初始化
        int x = BLACK;
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            for (int j = 0; j < GameUtil.LINE_COUNT; j++) {
                ChessBean chessBean = new ChessBean(i, j, EMPTY, 0);
                chessBeans[i][j] = chessBean;
            }
        }
        addMouseMotionListener(mouseMotionListener);
        addMouseListener(mouseListener);                //2个注册就监听器放在这里
        new ImageIcon("img/background.png").getImage();

    }

    protected void paintComponent( Graphics g ) {//重写JPanel的方法
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        //绘制棋盘线
        g2d.setStroke(new BasicStroke(3.0f));
        drawLine(g2d);
        //绘制天元和星
        drawStar(g2d);
        //绘制预选框
        drawTips(g2d, tx * 40, ty * 40);
        //drawTips(g2d ,GameUtil.LINE_COUNT/2+1,GameUtil.LINE_COUNT/2+1);
        //2种方式写字母和数字
        //drawChar(g2d);
        drawNumber(g2d);
        drawChess(g2d);
        if (isShowOrder) {
            drawOrderNum(g2d);
        }
        // g.drawImage(imgBack, 0, 0, this.getWidth(), this.getHeight(), this); // 绘制背景
    }

           /*
            private void drawChar(Graphics2D g2D) {
             int x,y;
                x=GameUtil.OFFSET;y=GameUtil.OFFSET;
                int t=1;
                char a[]=new char[GameUtil.LINE_COUNT];
                char b[]=new char[GameUtil.LINE_COUNT];
                for(int i=0;i<GameUtil.LINE_COUNT;i++){
                    a[i]=(char)(65+i);
                }

               for(int i=0;i<GameUtil.LINE_COUNT;i++){
                   String s=String.valueOf(GameUtil.LINE_COUNT-i);
                   g2D.drawString(s,GameUtil.OFFSET/2,i*GameUtil.CELL_WIDTH+GameUtil.OFFSET);
               }
        //字母
                for(int i=0;i<GameUtil.LINE_COUNT;i++) {
                    String s;
                    s=String.valueOf(a[i]);
                    g2D.drawString(s, i*GameUtil.CELL_WIDTH+GameUtil.OFFSET,
                    GameUtil.OFFSET+(GameUtil.CELL_WIDTH-1)*GameUtil.LINE_COUNT);

                }

            }
        */
    /*
        public void setImgBack(Image imgBack) {
            this.imgBack = imgBack;
        }
        public Image getImgBack() {
            return imgBack;
        }
    */
    //绘制预选框

    private void drawTips( Graphics2D g2D, int tx, int ty ) {
        g2D.setColor(Color.RED);
        //x=(GameUtil.LINE_COUNT / 2) * GameUtil.CELL_WIDTH+GameUtil.OFFSET;
        //y=(GameUtil.LINE_COUNT/2)*GameUtil.CELL_WIDTH+GameUtil.OFFSET;
        int x = tx, y = ty;
        //x=chessBeans[tx][ty].getX();
        //y=chessBeans[tx][ty].getY();

        //左上角向右的线
        g2D.drawLine(x - GameUtil.CELL_WIDTH / 2,
                y - GameUtil.CELL_WIDTH / 2,
                x - GameUtil.CELL_WIDTH / 4,
                y - GameUtil.CELL_WIDTH / 2);


        //绘制左上角向下的线
        g2D.drawLine(x - GameUtil.CELL_WIDTH / 2,
                y - GameUtil.CELL_WIDTH / 2,
                x - GameUtil.CELL_WIDTH / 2,
                y - GameUtil.CELL_WIDTH / 4);


        //  绘制左下角向上
        g2D.drawLine(x - GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 2,
                x - GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 4);


        //绘制左下角向右
        g2D.drawLine(x - GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 2,
                x - GameUtil.CELL_WIDTH / 4, y + GameUtil.CELL_WIDTH / 2);


        //右上角向左的线
        g2D.drawLine(x + GameUtil.CELL_WIDTH / 2, y - GameUtil.CELL_WIDTH / 2,
                x + GameUtil.CELL_WIDTH / 4, y - GameUtil.CELL_WIDTH / 2);


        //绘制右上角向下的线
        g2D.drawLine(x + GameUtil.CELL_WIDTH / 2, y - GameUtil.CELL_WIDTH / 2,
                x + GameUtil.CELL_WIDTH / 2, y - GameUtil.CELL_WIDTH / 4);


        //  绘制右下角向上
        g2D.drawLine(x + GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 2,
                x + GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 4);


        //绘制右下角向左
        g2D.drawLine(x + GameUtil.CELL_WIDTH / 2, y + GameUtil.CELL_WIDTH / 2,
                x + GameUtil.CELL_WIDTH / 4, y + GameUtil.CELL_WIDTH / 2);
        g2D.setColor(Color.BLACK);
    }

    //绘制天元和星
    private void drawStar( Graphics2D g2d ) {
        //在x,y绘制一个点，drawOval绘制的是一个空心(到圆心距离）
        //计算天元的点的坐标是40
        //计算天元的星
        g2d.fillOval((GameUtil.LINE_COUNT / 2) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                (GameUtil.LINE_COUNT / 2) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                GameUtil.STAR_WIDTH, GameUtil.STAR_WIDTH
        );

        //  g2d.fillOval((15/2)*40+40-4,(15/2)*40+40-4,8,8);


        //左上角的星

        g2d.fillOval((GameUtil.LINE_COUNT / 4) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                (GameUtil.LINE_COUNT / 4) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                GameUtil.STAR_WIDTH, GameUtil.STAR_WIDTH
        );


        //左下角的星

        g2d.fillOval((GameUtil.LINE_COUNT / 4) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                (GameUtil.LINE_COUNT - GameUtil.LINE_COUNT / 4 - 1) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                GameUtil.STAR_WIDTH, GameUtil.STAR_WIDTH
        );

        //右上角的星

      /*    空心椭圆

       g2d.drawOval((GameUtil.LINE_COUNT-GameUtil.LINE_COUNT / 4-1) * GameUtil.CELL_WIDTH+GameUtil.OFFSET-GameUtil.STAR_WIDTH/2,
                   (GameUtil.LINE_COUNT/4)*GameUtil.CELL_WIDTH+GameUtil.OFFSET-GameUtil.STAR_WIDTH/2,
                   GameUtil.STAR_WIDTH,GameUtil.STAR_WIDTH
           );

           */

        g2d.fillOval((GameUtil.LINE_COUNT - GameUtil.LINE_COUNT / 4 - 1) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                (GameUtil.LINE_COUNT / 4) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                GameUtil.STAR_WIDTH, GameUtil.STAR_WIDTH
        );

        //右下角的星

        g2d.fillOval((GameUtil.LINE_COUNT - GameUtil.LINE_COUNT / 4 - 1) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                (GameUtil.LINE_COUNT - GameUtil.LINE_COUNT / 4 - 1) * GameUtil.CELL_WIDTH + GameUtil.OFFSET - GameUtil.STAR_WIDTH / 2,
                GameUtil.STAR_WIDTH, GameUtil.STAR_WIDTH
        );

    }


    //绘制预选框
    private void drawLine( Graphics g2d ) {
        //偏移量 x,y都是40
        int offset = 40;
        //2条线之间的距离
        int cell_width = 40;
        //从(x1,y1)到(x2,y2)画一条线
        //画横线x不变，y变
        for (int i = 0; i < 15; i++) {
            g2d.drawLine(offset, offset + i * cell_width, offset + (15 - 1) * cell_width, offset + i * cell_width);
        }
        //画竖线
        for (int i = 0; i < 15; i++) {
            g2d.drawLine(offset + i * cell_width, offset, offset + i * cell_width, offset + (15 - 1) * cell_width);
        }
    }

    //绘制棋盘上已下棋子
    private void drawChess( Graphics2D g2D ) {
        int WIDTH = GameUtil.CELL_WIDTH / 4 * 3;
        for (ChessBean[] chessBeans2 : chessBeans) {
            for (ChessBean chessBean : chessBeans2) {
                if (!chessBean.isEmpty()) {   //如果chessBean是空，则绘制
                    if (chessBean.getPlayer() == BLACK) {
                        g2D.setColor(Color.BLACK);
                    } else if (chessBean.getPlayer() == WHITE) {
                        g2D.setColor(Color.WHITE);
                    }
                    //计算像素坐标
                    int x = chessBean.getX() * GameUtil.CELL_WIDTH + GameUtil.OFFSET - WIDTH / 2;
                    int y = chessBean.getY() * GameUtil.CELL_WIDTH + GameUtil.OFFSET - WIDTH / 2;
                    g2D.fillOval(x, y, WIDTH, WIDTH);
                }

            }
        }
    }

    private void drawNumber( Graphics2D g2d ) {

        Font font = new Font("微软雅黑", Font.BOLD, 14);
        g2d.setFont(font);
        FontMetrics fm = g2d.getFontMetrics();
        int heigth = fm.getAscent();//获取文本的高度
        //int width=fm.stringWidth(str1[0]);

        //绘制数字，列方向
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            int x = 9;//GameUtil.OFFSET;
            int y = i * GameUtil.CELL_WIDTH + GameUtil.OFFSET + heigth / 2;
            g2d.drawString((GameUtil.LINE_COUNT - i) + " ", x, y);
        }

        //绘制字母
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            int base = (int) 'A';
            int x = i * GameUtil.CELL_WIDTH + GameUtil.OFFSET;
            int y = GameUtil.LINE_COUNT * GameUtil.CELL_WIDTH + GameUtil.OFFSET;
            g2d.drawString((char) (base + i) + "", x, y);
        }

    }


    private void drawOrderNum( Graphics2D g2D ) {
        //currentPlayer = BLACK;
        FontMetrics fm = g2D.getFontMetrics();
        fm.getAscent();
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            for (int j = 0; j < GameUtil.LINE_COUNT; j++) {
                if (chessBeans[i][j].getOrderNum() != 0) {
                    if (chessBeans[i][j].getPlayer() == BLACK) {
                        g2D.setColor(Color.WHITE);
                    } else if (chessBeans[i][j].getPlayer() == WHITE)
                        g2D.setColor(Color.BLACK);
                    g2D.drawString(chessBeans[i][j].getOrderNum() + " ",
                            chessBeans[i][j].getX() * GameUtil.CELL_WIDTH + GameUtil.OFFSET,
                            chessBeans[i][j].getY() * GameUtil.CELL_WIDTH + GameUtil.OFFSET);
                    //g2D.fillOval(i,j,WIDTH,WIDTH);
                    //currentPlayer = 3 - currentPlayer;//多此一举
                }
            }
        }
        g2D.setColor(Color.RED);
        int rec_width = GameUtil.CELL_WIDTH / 5;
        g2D.fillRect(getMaxOrderNum().getX() * GameUtil.CELL_WIDTH + GameUtil.OFFSET - rec_width / 2,
                getMaxOrderNum().getY() * GameUtil.CELL_WIDTH + GameUtil.OFFSET - rec_width / 2,
                rec_width, rec_width);
    }

    public ChessBean getMaxOrderNum() {
        ChessBean tmp = chessBeans[0][0];
        for (ChessBean[] chessBean2 : chessBeans) {
            for (ChessBean chessBean : chessBean2) {
                if (tmp.getOrderNum() <= chessBean.getOrderNum()) {
                    tmp = chessBean;
                }
            }
        }
        return tmp;
    }
    private MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {
        public void mouseMoved( MouseEvent e ) {
            int x = e.getX();
            int y = e.getY();
            //转化为线坐标
            tx = (x - GameUtil.OFFSET / 2) / GameUtil.CELL_WIDTH + 1;
            ty = (y - GameUtil.OFFSET / 2) / GameUtil.CELL_WIDTH + 1;
            //System.out.printf("%d %d\n",tx,ty);
            if (tx > GameUtil.LINE_COUNT) {
                tx = 15;
            }
            if (ty > GameUtil.LINE_COUNT) {
                ty = 15;
            }
            repaint();
        }
    };

    ChessBean chessTreeBean = null;

    private MouseListener mouseListener = new MouseAdapter() {
        //重写坐标,点击函数
        public void mouseClicked( MouseEvent e ) {
            int x = e.getX();
            int y = e.getY();
            //转化为线坐标
            x = (x - GameUtil.OFFSET / 2) / GameUtil.CELL_WIDTH;
            y = (y - GameUtil.OFFSET / 2) / GameUtil.CELL_WIDTH;

            if (isGameOver) {
                JOptionPane.showMessageDialog(GamePanel.this, "请点击游戏开始");
                return;
            }
            if(e.getButton()==e.BUTTON1)//鼠标左键被点击
            {
                if (x >= 0 && x < GameUtil.LINE_COUNT && y < GameUtil.LINE_COUNT && y >= 0) {
                    if (mode) {    //人人
                        //把x,z这个chessBean添加到chessBeans
                        if (chessBeans[x][y].isEmpty()) {
                            //该位置可以下棋
                            chessBeans[x][y] = new ChessBean(x, y, currentPlayer, count);
                            if(soundswitch){ music.putVoice(); }
                            currentPlayer = 3 - currentPlayer;//切到对方
                            count++;
                            System.out.println((chessBeans[x][y].getPlayer() == BLACK ? "黑子" : chessBeans[x][y].getPlayer() == WHITE ? "白子" : "未知") + "下棋完毕");
                            checkWin(x, y, chessBeans[x][y].getPlayer());
                        }
                    }
                    else {//人机
                        if (intel)
                        {
                            //估值函数，接下来由白子下棋
                            //  System.out.println(count);
                            if (chessBeans[x][y].isEmpty()) {
                                //该位置可以下棋
                                chessBeans[x][y] = new ChessBean(x, y, WHITE, count);
                                if(soundswitch) {
                                    music.putVoice();
                                }
                                if(soundswitch)  { count++;music.putVoice();}
                                System.out.println("白棋下的位置：x="+x + ",y=" + y);
                                System.out.println("白棋下子完毕！");
                                repaint();
                                System.out.println(!checkWin(x, y, chessBeans[x][y].getPlayer()));
                                if (!checkWin(x, y, chessBeans[x][y].getPlayer()))
                                {
                                    //电脑下棋,找到估值最大的(x,y)
                                    List<ChessBean> orderList = getSortList(BLACK, chessBeans);
                                    ChessBean bean = orderList.get(0);
                                    x = bean.getX();
                                    y = bean.getY();
                                    System.out.println("黑棋下的位置：x="+x + ",y=" + y);
                                    bean.setPlayer(BLACK);
                                    bean.setOrderNum(count);
                                    chessBeans[x][y] = bean;
                                    count++;
                                    if(soundswitch) { music.putVoice();}
                                    System.out.println("黑子下棋完毕！");
                                    checkWin(x, y, chessBeans[x][y].getPlayer());
                                }
                            }
                        }

                        else {
                            //估值函数+搜索树
                            if (chessBeans[x][y].isEmpty())
                            {
                                //该位置可以下棋
                                chessBeans[x][y] = new ChessBean(x, y, WHITE, count);
                                count++;
                                if(soundswitch){ music.putVoice();}
                                System.out.println("白子下棋完毕！");
                                repaint();
                                System.out.println(!checkWin(x, y, chessBeans[x][y].getPlayer()));
                                if (!checkWin(x, y, chessBeans[x][y].getPlayer())) {
                                    //电脑下棋,找到估值最大的(x,y)
                                    getValueByTree2(0, BLACK, chessBeans, -Integer.MAX_VALUE, Integer.MAX_VALUE);
                                    ChessBean bean = chessTreeBean;
                                    x = bean.getX();
                                    y = bean.getY();
                                    bean.setPlayer(BLACK);
                                    bean.setOrderNum(count);
                                    chessBeans[x][y] = bean;
                                    count++;
                                    if(soundswitch){ music.putVoice();}
                                    System.out.println("黑子下棋完毕！");
                                    checkWin(x, y, chessBeans[x][y].getPlayer());
                                    repaint();
                            /*
                                if(chessBeans[x][y].isEmpty()) {
                                    //该位置可以下棋
                                    chessBeans[x][y] = new ChessBean(x, y, WHITE, count);
                                    count ++;
                                    System.out.println("白子下棋完毕！");
                                    repaint();
                                    if(!checkWin(x, y, chessBeans[x][y].getPlayer())) {
                                        //电脑下棋,找到估值最大的(x,y)
                                        ChessBean bean = getValueByTree1(0, BLACK, chessBeans);
                                        x = bean.getX();
                                        y = bean.getY();
                                        bean.setPlayer(BLACK);
                                        bean.setOrderNum(count);
                                        chessBeans[x][y] = bean;
                                        count++; if(soundswitch){music.putVoice();}
                                        System.out.println("黑子下棋完毕！");
                                        checkWin(x, y, chessBeans[x][y].getPlayer());

                                    }
                                    */
                                }
                            }
                        }
                        repaint();
                    }
                }
            }

            else if(e.getButton()==e.BUTTON3) {
                x=e.getX();
                y=e.getY();
                x=(x-GameUtil.OFFSET/2)/GameUtil.CELL_WIDTH;
                y=(y-GameUtil.OFFSET/2)/GameUtil.CELL_WIDTH;
                System.out.println(getSortList( currentPlayer, chessBeans).get(0));
                GameFrame.area.append("\t\t\t"+getSortList( currentPlayer, chessBeans).get(0).toString()+"\n");
                if(checkWin(x,y,currentPlayer)){
                    GameFrame.area.append("\t\t\t恭喜"+currentPlayer+"赢了"+"\n");
                }
            }
        }
    };




    //悔棋
    public void undo() {
        //获取四个方向其形
        ChessBean temp = getMaxOrderNum();
        if (!temp.isEmpty()) {
            currentPlayer = temp.getPlayer();
            temp.setPlayer(0);
            temp.setOrderNum(0);
            count--;
            repaint();
        }
    }
    //新游戏
    public void newGame( boolean selected,boolean mode, boolean intel, int depthTmp, int nodeCountTmp ) {
        startTime = System.currentTimeMillis();    //获取开始时间
        isGameOver = false;
        this.mode = mode;
        this.intel = intel;
        this.depth=depthTmp;
        this.nodeCount=nodeCountTmp;
        currentPlayer = BLACK;
        count = 1;
        chessBeans = new ChessBean[GameUtil.LINE_COUNT][GameUtil.LINE_COUNT];
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            for (int j = 0; j < GameUtil.LINE_COUNT; j++) {
                ChessBean chessBean = new ChessBean(i, j, EMPTY, 0);
                chessBeans[i][j] = chessBean;
            }
        }
        if(mode==false){
            //在中心加黑子
            tx = (GameUtil.LINE_COUNT / 2);
            ty = (GameUtil.LINE_COUNT / 2);
            chessBeans[tx][ty].setPlayer(BLACK);
            chessBeans[tx][ty].setOrderNum(count);
            count++;
            currentPlayer = 3 - currentPlayer;
            isGameOver=false;
            isShowOrder=selected;
        }
        JOptionPane.showMessageDialog(GamePanel.this, "游戏开始");
        repaint();

    }



    //显示棋盘上的棋子顺序
    public void ShowOrder() {
        isShowOrder = !isShowOrder;
        repaint();
    }
            /*  public void showOrderNumber(boolean selected) {
            isShowOrder = selected;
            repaint();
             }
             */

    //判断规则，向某个棋子的4个方向判断
    private int check( int x, int y, int dx, int dy, int player ) {
        int count = 0;
        for (int i = 0; i < 4; i++) {
            x += dx;
            y += dy;
            if (x >= 0 && x < GameUtil.LINE_COUNT && y >= 0 && y < GameUtil.LINE_COUNT) {
                if (chessBeans[x][y].getPlayer() == player) {
                    count++;
                } else {
                    break;
                }
            }

        }
        return count;
    }

    //检查是否5个子相连，（1，0）向右，（-1，0）向左
    private boolean checkWin( int x, int y, int player ) {
        boolean win = false;
        if (check(x, y, 1, 0, player) + check(x, y, -1, 0, player) + 1 >= 5) {
            win = true;
        } else if (check(x, y, 0, 1, player) + check(x, y, 0, -1, player) + 1 >= 5) {
            win = true;
        } else if (check(x, y, 1, 1, player) + check(x, y, -1, -1, player) + 1 >= 5) {
            win = true;
        } else if (check(x, y, -1, 1, player) + check(x, y, 1, -1, player) + 1 >= 5) {
            win = true;
        }
        if (win) {
            endTime = System.currentTimeMillis();    //获取结束时间
            Calendar c = Calendar.getInstance();
            String nowtime = c.get(YEAR) +"年"+(c.get(MONTH)+1)+" 月"+(c.get(Calendar.DAY_OF_MONTH)) +"日" +c.get(Calendar.HOUR_OF_DAY) + "时" + c.get(Calendar.MINUTE) + "分" + c.get(Calendar.SECOND)+"秒";
            GameFrame.area.append("\t\t\t\t\t"+"本次结束游戏的时间是"+nowtime+'\n');
            GameFrame.area.append("\t\t\t\t\t"+"本次游戏程序运行的总时间：" + (endTime - startTime) + "ms"+'\n');

            System.out.println(player);
            if(soundswitch) {
                if (mode == true) {
                    music.winVoice();
                } else if (player == WHITE && mode == false) {
                    music.winVoice();
                } else if (player == BLACK && mode == false) {
                    music.lostVoice();
                }
            }
            GameFrame.area.append("\t\t\t\t\t"+"恭喜"+(player == BLACK? "BLACK":"WHITE" )+"赢了"+"\n");
            JOptionPane.showMessageDialog(GamePanel.this, (player == BLACK ? "BLACK" : "WHITE") + " win！");
            isGameOver = true;
            return true;
        }
        return false;
    }


    //renji

    //遍历每层，找到估值大于一定程度的点
    protected ChessBean getValueByTree1( int d, int player, ChessBean[][] chessBeans ) {
        ChessBean[][] tmp = clone(chessBeans);
        List<ChessBean> orderList = getSortList(player, chessBeans);
        if (d == depth) {
            //达到搜索指定深度,返回当前获取估值最高的点
            return orderList.get(0);
        }//遍历当前所有的空余位置(获取getSortList)
        for (int i = 0; i < orderList.size(); i++) {
            ChessBean bean = orderList.get(i);
            if (bean.getSum() > Level.ALIVE_4.score) {
                //找到目标
                return bean;
            } else {
                //这个是模拟下棋，不能真正地在棋盘上落子
                chessBeans[bean.getX()][bean.getY()].setPlayer(player);
                return getValueByTree1(d + 1, player, tmp);
            }
        }
        return null;
    }



    private ChessBean[][] clone( ChessBean[][] chessBeans ) {
        ChessBean[][] tmp = new ChessBean[GameUtil.LINE_COUNT][GameUtil.LINE_COUNT];
        for (int i = 0; i < GameUtil.LINE_COUNT; i++) {
            for (int j = 0; j < GameUtil.LINE_COUNT; j++) {
                tmp[i][j] = new ChessBean(chessBeans[i][j].getX(), chessBeans[i][j].getY(), chessBeans[i][j].getPlayer(), chessBeans[i][j].getOrderNum());
            }
        }
        return tmp;
    }

    protected int getValueByTree2( int d, int player, ChessBean[][] chessBeans, int alpha, int beta ) {
        ChessBean[][] tmp = clone(chessBeans);
        List<ChessBean> orderList = getSortList(player, tmp);
        if (d == depth) {
            //达到搜索指定深度，结束。返回当前步骤中。获取到的估值最高的点。
            return orderList.get(0).getSum();
        }
        //遍历当前棋盘上所有空余的位置（遍历getSortList）
        for (int i = 0; i < nodeCount; i++) {
            int score = 0;
            ChessBean bean = orderList.get(i);
            if (bean.getSum() >= Level.ALIVE_4.score) {
                //找到目标
                score = bean.getSum();
            } else {
                //这个步骤是模拟下棋。不能再真正的棋盘上进行落子
                tmp[bean.getX()][bean.getY()].setPlayer(player);
                score = getValueByTree2(d + 1, 3 - player, tmp, alpha, beta);
            }


            if(d%2==0) {
                //自己，找最大值
                if(score>alpha) {
                    alpha = score;
                    if(d==0) {
                        //结果
                        chessTreeBean = bean;
                    }
                }
                if(alpha>=beta) {
                    //剪枝
                    score = alpha;
                    return score;
                }
            } else {

                if(score<beta) {
                    beta = score;
                }
                if(alpha>=beta) {
                    //剪枝
                    score = beta;
                    return score;
                }

            }
        }
        return d%2==0?alpha:beta;
    }



    public static enum Level {
        CON_5("长连", 0, new String[] { "11111", "22222" }, 100000),
        ALIVE_4("活四", 1, new String[] { "011110", "022220" }, 1000),
        GO_4("冲四", 2, new String[] { "011112|0101110|0110110",
                "022221|0202220|0220220" }, 500),
        DEAD_4("死四", 3,new String[] { "211112", "122221" }, -5),
        ALIVE_3("活三", 4,new String[] { "01110|010110", "02220|020220" }, 200),
        SLEEP_3("眠三", 5, new String[] {
                "001112|010112|011012|10011|10101|2011102",
                "002221|020221|022021|20022|20202|1022201" }, 50),
        DEAD_3("死三", 6, new String[] { "21112", "12221" }, -5),
        ALIVE_2("活二",7, new String[] { "00110|01010|010010", "00220|02020|020020" },5),
        SLEEP_2("眠二", 8, new String[] {
                "000112|001012|010012|10001|2010102|2011002",
                "000221|002021|020021|20002|1020201|1022001" }, 3),
        DEAD_2("死二", 9, new String[] { "2112", "1221" }, -5),
        NULL("null", 10,new String[] { "", "" }, 0);
        private String name;
        private int index;
        private String[] regex;// 正则表达式
        int score;// 分值

        // 构造方法
        private Level( String name, int index, String[] regex, int score ) {
            this.name = name;
            this.index = index;
            this.regex = regex;
            this.score = score;
        }

        // 覆盖方法
        @Override
        public String toString() {
            return this.name;
        }
    }

    // 方向
    private static enum Direction {
        HENG, SHU, PIE, NA
    }

    // 位置分
    private static int[][] position = {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
            {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
            {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
            {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    };

    private int getLevel2Score(Level level1, Level level2, Level level3, Level level4) {
        int[] levelCount = new int[Level.values().length];
        for(int i=0; i<levelCount.length; i++) {
            levelCount[i] = 0;
        }
        //统计某一个棋型出现的次数
        levelCount[level1.index]++;
        levelCount[level2.index]++;
        levelCount[level3.index]++;
        levelCount[level4.index]++;
        int score = 0;
        if(levelCount[Level.CON_5.index]>=1) {
            score=100000;
        }
        else if(levelCount[Level.ALIVE_4.index]>=1) {
            score=50000;
        }else if (levelCount[Level.GO_4.index] >= 2
                || levelCount[Level.GO_4.index] >= 1
                && levelCount[Level.ALIVE_3.index] >= 1)// 双活4，冲4活三
            score = 10000;
        else if (levelCount[Level.ALIVE_3.index] >= 2)// 双活3
            score = 5000;
        else if (levelCount[Level.SLEEP_3.index] >= 1
                && levelCount[Level.ALIVE_3.index] >= 1)// 活3眠3
            score = 1000;
        else if (levelCount[Level.ALIVE_2.index] >= 2)// 双活2
            score = 100;
        else if (levelCount[Level.SLEEP_2.index] >= 1
                && levelCount[Level.ALIVE_2.index] >= 1)// 活2眠2
            score = 10;
        return Math.max(score, Math.max(Math.max(level1.score, level2.score), Math.max(level3.score, level4.score)));
    }


    //计算四个方向的棋型，获取Level


    private Level getLevel(int x, int y, Direction dir, int player, ChessBean[][] tmp) {
        String left = "";
        String right = "";
        if(dir==Direction.HENG) {
            left = getStringSeq(x, y, -1, 0, player, tmp);
            right = getStringSeq(x, y, 1, 0, player, tmp);
        } else if(dir==Direction.SHU) {
            left = getStringSeq(x, y, 0, -1, player, tmp);
            right = getStringSeq(x, y, 0, 1, player, tmp);
        } else if(dir==Direction.PIE) {
            left = getStringSeq(x, y, -1, 1, player, tmp);
            right = getStringSeq(x, y, 1, -1, player, tmp);
        } else if(dir==Direction.NA) {
            left = getStringSeq(x, y, -1, -1, player, tmp);
            right = getStringSeq(x, y, 1, 1, player, tmp);
        }
        String str = left+player+right;
        chessBeans[x][y].getBuffer().append("direction:"+str+"\n");
        //获取棋型的倒置字符串
        String rstr = new StringBuffer(str).reverse().toString();
        //根据str和rstr去Level里进行棋型匹配
        for(Level level:Level.values()) {
            Pattern pattern = Pattern.compile(level.regex[player-1]);
            Matcher matcher = pattern.matcher(str);
            //如果是true则匹配成功
            boolean r1 = matcher.find();
            matcher = pattern.matcher(rstr);
            //如果是true则匹配成功
            boolean r2 = matcher.find();
            if(r1||r2) {
                return level;
            }
        }
        //System.out.println("x:"+x+",y:"+y+",dir:"+dir+",str:"+str);
        return Level.NULL;
    }

    protected int getValue(int x, int y, int player, ChessBean[][] tmp) {
        Level level1 = getLevel(x, y, Direction.HENG, player, tmp);
        Level level2 = getLevel(x, y, Direction.SHU, player, tmp);
        Level level3 = getLevel(x, y, Direction.PIE, player, tmp);
        Level level4 = getLevel(x, y, Direction.NA, player, tmp);
        return getLevel2Score(level1, level2, level3, level4)+position[x][y];
    }


    //从(x,y)出发，有8个方向的线，4个保持原有。4个字符串首尾调换
    private String getStringSeq(int x, int y, int dx, int dy, int player, ChessBean[][] tmp) {
        String str = "";
        boolean res = false;
        //判断有哪4条线需要倒置
        if(dx<0||(dx==0&&dy<0)) {
            res = true;
        }
        for(int i=0; i<5; i++) {
            x += dx;
            y += dy;

            if(x>=0&&x<GameUtil.LINE_COUNT&&y>=0&&y<GameUtil.LINE_COUNT) {
                if(res) {
                    str = tmp[x][y].getPlayer() + str;
                } else {
                    str = str + tmp[x][y].getPlayer();
                }
            }
        }
        return str;
    }

    //计算空余未知的估值，然后排序
    private List<ChessBean> getSortList( int player, ChessBean[][] tmp ) {
        List<ChessBean> list = new ArrayList<>();
        for (ChessBean[] chessBeans2 : tmp) {
            for (ChessBean chessBean : chessBeans2) {
                //找到空点
                if (chessBean.isEmpty()) {
                    //计算自己得分
                    int o = getValue(chessBean.getX(), chessBean.getY(), player,tmp);
                    //计算对方得分
                    int d = getValue(chessBean.getX(), chessBean.getY(), 3 - player,tmp);
                    chessBean.setDefense(d);
                    chessBean.setOffense(o);
                    chessBean.setSum(d + o);
                    list.add(chessBean);
                }
            }
        }
        Collections.sort(list);
        return list;
    }




    public Music getMusic() {
        return music;
    }
    public void setMusic(Music music) {
        this.music = music;
    }
    public void setSoundswitch(boolean soundswitch) {
        this.soundswitch = soundswitch;
    }
}

